package cn.nexd.map.coreLocator;

import java.util.ArrayList;
import java.util.List;

/**
 * Created by admin on 15/8/29.
 */


public class coreLocationEngine {
    private Double[] markovProb;
    private Double[][] markovPos;
    private Double[][] opt;
    private int probLength;
    private int wifiLength;



    /*

     */


    private List<Double[]> temp_opt;

    private Double sum = 0.0;
    private Double m_a = 0.0;
    private Double m_b = 0.0;
    private Double comp1 = 0.0;
    private Double comp2 = 0.0;
    private Double comp3 = 0.0;
    private Double[] prob;
    private Double[] temp;
    private Double[] diff = new Double[2];
    private Double[] tempres = new Double[2];


    private Double[][] preRes = null;


    /* Integrated Function */
    public Double[] locate(Double[] wifi) {
        Double[] prob = locationEngine(wifi);
        Double[] res = getPos(prob);
        return res;
    }

    private List<Integer> indexNonZero(Double[] wifi) {
        List<Integer> res = new ArrayList<>();
        for (int j = 0; j < this.wifiLength; j++) {
            temp[j] = 0.0;
            if (wifi[j] == 0. || opt[j][0] == -1. || opt[j][7] < 1e-2) {
                continue;
            }

            res.add(j);
        }
        return res;
    }

    private void testSpeed2(Double[] wifi) {
        List<Integer> index = indexNonZero(wifi);
        int L = index.size();
        for (int i = 0; i < this.probLength; i++) {
            for (int j = 0; j < L; j++) {
                index.get(j);
            }
            for (int j = 0; j < L; j++) {
                index.get(j);
            }
        }
    }

    public void initMarkov(Double[][] opt, Double[][] pos) {
        this.probLength = pos.length;
        this.wifiLength = opt.length;
        this.temp_opt = new ArrayList<>();
        this.markovProb = new Double[this.probLength];
        for (int i = 0; i < this.probLength; i++) {
            this.markovProb[i] = 0.0;

        }
        for (int j = 0; j < this.wifiLength; j++) {
            temp_opt.add(opt[j]);
        }
        this.markovPos = pos.clone();
        this.opt = opt.clone();


        /*

         */
        this.temp = new Double[this.wifiLength];
        this.prob = new Double[this.probLength];
        this.preRes = null;
    }


    public Double[] locationEngine(Double[] wifi) {
        //        for (int i = 0; i < wifi.length; i++) {
        //            if (wifi[i] != 0.0) {
        //                Log.d(coreLocationEngine.this, "++++" + String.valueOf(wifi[i]));
        //            }
        //        }
        //        Log.d(coreLocationEngine.this, "+++=============================================华丽的分割线====================================================");


        if (this.preRes == null) {
            this.preRes = new Double[this.probLength][this.wifiLength];
            for (int j = 0; j < this.probLength; j++) {
                for (int i = 0; i < this.wifiLength; i++) {
                    diff[0] = markovPos[j][0] - opt[i][1];
                    diff[1] = markovPos[j][1] - opt[i][2];
                    tempres[0] = diff[0] * opt[i][3] + diff[1] * opt[i][4];
                    tempres[1] = diff[0] * opt[i][4] + diff[1] * opt[i][5];
                    Double dis = Math.sqrt(tempres[0] * diff[0] + tempres[1] * diff[1]);
                    Double pre = opt[i][0] - 10 * opt[i][6] * Math.log10(dis + 1);
                    preRes[j][i] = (pre <= 10. || pre.isNaN()) ? 0.0 : pre;
                }
            }
        }

        List<Integer> index = new ArrayList<>();
        for (int j = 0; j < this.wifiLength; j++) {
            temp[j] = 0.0;
            if (wifi[j] == 0. || opt[j][0] == -1. || opt[j][7] < 1e-2) {
                continue;
            }
            Double w = (wifi[j] + 1.0) / 100.0;
            sum += w;
            m_a += wifi[j] * w;
            index.add(j);
        }
        m_a /= sum;
        int L = index.size();

        for (int j = 0; j < this.probLength; j++) {
            m_b = 0.0;
            comp1 = 0.0;
            comp2 = 0.0;
            comp3 = 0.0;
            for (int n = 0; n < L; n++) {
                int i = index.get(n);
                //                diff[0] = markovPos[j][0] - opt[i][1];
                //                diff[1] = markovPos[j][1] - opt[i][2];
                //                tempres[0] = diff[0] * opt[i][3] + diff[1] * opt[i][4];
                //                tempres[1] = diff[0] * opt[i][4] + diff[1] * opt[i][5];
                //                Double dis = Math.sqrt(tempres[0] * diff[0] + tempres[1] * diff[1]);
                //                Double pre = opt[i][0] - 10 * opt[i][6] * Math.log10(dis + 1);
                //                temp[i] = (pre <= 10. || pre.isNaN()) ? 0.0 : pre;

                //                if(pre !=0){
                //                    m_b += pre * (wifi[i] + 1.0)/100.0;
                //                }
                m_b += preRes[j][i] * (wifi[i] + 1.0) / 100.0;
            }
            m_b /= sum;
            for (int n = 0; n < L; n++) {
                int i = index.get(n);
                comp1 += (wifi[i] - m_a) * (preRes[j][i] - m_b);
                comp2 += (wifi[i] - m_a) * (wifi[i] - m_a);
                comp3 += (preRes[j][i] - m_b) * (preRes[j][i] - m_b);
            }
            prob[j] = (comp2 * comp3 == 0) ? 0.0 : comp1 / Math.sqrt(comp2 * comp3);
        }
        index = null;
        return prob;
    }


    private Double[] getPos(Double[] prob) {
        int index = argMax(prob);
        return this.markovPos[index];
    }

    private int argMax(Double[] prob) {
        int ind = 0;
        Double m = prob[ind];
        for (int i = 0; i < this.probLength; i++) {
            if (prob[i] > m) {
                ind = i;
                m = prob[i];
            }

            //            Log.d("prob", "" + prob[i]);
        }
        return ind;
    }
}






